import pandas as pd
from plotly.offline import download_plotlyjs, init_notebook_mode, plot, iplot
import plotly
import plotly.graph_objs as go
from datetime import date, timedelta
import plotly.express as px
import numpy as np
df = pd.read_csv('../data/report_task_2.csv')
df['Turn_off'] = False
df['profit'] = df['bids'] * df['bidFloor']
df.head()
Также нам нужно определить суммарный доход, и границу потерь
total_profit = int(df['profit'].sum())
decrease_allowed = int(total_profit * 0.05)
print(f'Total profit: {total_profit}, decrease in profit is allowed: {decrease_allowed}')
temp = df.copy()
temp = temp.groupby(['country', 'appId', 'agencyId', 'adType', 'bidFloor']).sum().reset_index()
temp['profit_diff_requests'] = temp['profit'] / temp['requests']
Сразу отправим на удаление те случае, когда bidFloor=0 и мы ничего не зарабатываем внезависимости от того, была ставка или нет.
Также исключим те случае, когда мы ничего не заработали, так как отсуствовали ставки:
temp.loc[(temp['bidFloor']==0), 'Turn_off'] = True
requests_save = df[(df['bidFloor']==0)]['requests'].sum()
print(f'Requests save: {requests_save}')
temp.loc[temp['profit']==0, 'Turn_off'] = True
requests_save += temp[temp['profit']==0]['requests'].sum()
print(f'Requests save: {requests_save}')
Посмотрим на расспределение соотношения профита к риквестам. Ограничем его справа 0.1, для лучшей наглядности.
Как мы видим, у нас очень много риквестов сконцентрированно на низко профитном трафике.
fig = px.histogram(temp[(temp['profit_diff_requests']<0.1)
&(temp['Turn_off']==False)][['profit_diff_requests', 'requests']],
x='profit_diff_requests',
y='requests', histfunc="sum", nbins=10)
fig.show()
Посмотрим, сколько денег мы потеряем, если его отключим:
t = temp[(temp['profit_diff_requests']<0.01)&(temp['Turn_off']==False)]
decrease_in_profit = int(t['profit'].sum())
r_s = t['requests'].sum()
print(f'Requests save: {r_s}, decrease in profit: {decrease_in_profit}')
Согласно нашим ограничением, мы можем потерять 82287, при текущих ограничениях теряем 81612. Исключим этот трафик.
temp.loc[(temp['profit_diff_requests']<0.01)&(temp['Turn_off']==False), 'Turn_off'] = True
t = temp[temp['Turn_off']==True]
decrease_in_profit = int(t['profit'].sum())
r_s = t['requests'].sum()
print(f'Requests save: {r_s}, decrease in profit: {decrease_in_profit}')
В итоге, мы можем уменьшить объем риквествов на 285М, при этом потеряв всего 81612, что составляет ~5%
temp[temp['Turn_off']==True][['country', 'appId', 'agencyId',
'adType', 'bidFloor','requests']].to_csv('../data/saved_requests.csv', index=False)
Вывод:
Аналитический подход имеет место быть, но считаю его не самым оптимальным, там как на самом деле на ставку или ее отсуствие от ДСП влияет очень много параметров: сезонность, информация с риквества (девайс, вид рекламы, гео, пользователь и тд), история бидов этой ДСП и тд.
Это все приводит нас к использованию машинного обучения для решения подобных задач.
Самый простой вариант:
Для каждого риквества мы считаем вероятность бида и затем используем трешхолд по которому исключаем трафик. Для управления трехолдом можно использовать PID контроллер.